#ifndef _CCGEN_H_
#define _CCGEN_H_

#include <tbb/flow_graph.h>
#include <windows.h>
#include <vector>
#include <cassert>

class CCGenGpu;

#define CP_PI   3.14159265358979323846
#define CP_PIF   3.14159265358979323846F

enum EPixelFormat
{
	ePF_UNKNOWN,
	ePF_R8G8BA8,
	ePF_R8G8BA8_UINT,
	ePF_R16G16B16A16F,
	ePF_VECTOR,
	ePF_COUNT,
};

int epf_pixel_size(EPixelFormat format);

enum ECosPowerMipMode
{
	CP_COSINEPOWER_CHAIN_DROP = 0,
	CP_COSINEPOWER_CHAIN_MIPMAP = 1
};

enum
{
	MAX_CUBEMAP_MIPLEVEL = 16
};

enum ELUTStatus
{
	eLUTS_invalid,
	eLUTS_in_progress,
	eLUTS_ready
};

// Lighting model
enum ELightingModel
{
	CP_LIGHTINGMODEL_PHONG		=	0,
	CP_LIGHTINGMODEL_PHONG_BRDF	=	1,
	CP_LIGHTINGMODEL_BLINN		=	2,
	CP_LIGHTINGMODEL_BLINN_BRDF	=	3,
};

enum EFixupType
{
	CP_FIXUP_NONE            = 0,
	CP_FIXUP_PULL_LINEAR     = 1,
	CP_FIXUP_PULL_HERMITE    = 2,
	CP_FIXUP_AVERAGE_LINEAR  = 3,
	CP_FIXUP_AVERAGE_HERMITE = 4,
	CP_FIXUP_BENT			 = 5,
	CP_FIXUP_WARP			 = 6,
	CP_FIXUP_STRETCH		 = 7
};


struct SCubeFace
{
	unsigned int width;
	unsigned int height;

	void *dataPtr;
	unsigned int dataSize;

	SCubeFace()
		:width(0),
		height(0),
		dataPtr(nullptr),
		dataSize(0)
	{}

	void Clear();
};

struct SCubeMap
{
	EPixelFormat pixelFormat;	
	unsigned int width;
	unsigned int height;
	unsigned int mipCount;

	SCubeFace *faces;

	tbb::atomic<ELUTStatus> internalStatus;

	SCubeMap()
		:pixelFormat(ePF_UNKNOWN),
		width(0),
		height(0),
		mipCount(0)
	{
		internalStatus = eLUTS_invalid;
	}

	~SCubeMap()
	{
		SAFE_DELETE_ARRAY(faces);
	}
};


enum EFilterJobFlags
{
};

struct SFilterStateDesc
{
	int					dstSize;
	EPixelFormat		dstPixelFormat;
	EPixelFormat		srcPixelFormat;
	int					srcSize;
	EFixupType			fixupType;
	ECosPowerMipMode	mipMode;
	float				glossScale;
	float				glossBias;
	ELightingModel		lightingModel;
	float				specularPower;
	float				cosPowerDrop;
	bool				excludeBase;
};

struct SFilterState
{
private:
	int stateID;

public:
	int GetStateID() const
	{
		return stateID;
	}

	SFilterState(int _stateID)
	{
		stateID = _stateID;
	}
	
	SFilterState()
		:stateID(-1)
	{}

};

struct SFilterJob
{
	SCubeMap *inputCubemap;
	SCubeMap **outputCubemap;

	//see EFilterJobFlags
	unsigned int flags;

	SFilterState* filterState;


	void (*onCompleteCallback)(void *userPtr);
	void *userPtr;

	SFilterJob()
	{
		inputCubemap = nullptr;
		outputCubemap = nullptr;
		flags = 0;
		filterState = nullptr;
		onCompleteCallback = nullptr;
	}
};

class CJobDispatcher;

class CCGen
{

private:

	CJobDispatcher *dispatcher;

public:

	CCGen();

	~CCGen();


	bool Init();

	void AddFilterJob(const SFilterJob *newJob);

	bool CreateFilterState(const SFilterStateDesc* stateDesc, SFilterState** outState);

	void WaitForAll();

	bool EnableGpu();

	bool IsGpuEnabled();
};

#endif